package com.example.log.alarm.config;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.example.log.alarm.advice.exeception.ThrowableAdviceInterceptor;
import com.example.log.alarm.advice.logger.LoggerAdviceInterceptor;
import com.example.log.alarm.advice.thread.pool.RejectAdviceInterceptor;
import com.example.log.alarm.advice.thread.pool.ThreadPoolAdviceInterceptor;
import com.example.log.alarm.agent.AgentTemplate;
import com.example.log.alarm.agent.AgentVisitBase;
import com.example.log.alarm.constant.InterceptorType;
import com.example.log.alarm.manager.ErrorLogManager;
import com.example.log.alarm.manager.ThreadPoolManager;
import com.example.log.alarm.repository.MemoryRepository;
import com.example.log.alarm.repository.Repository;
import com.example.log.alarm.spy.BootstrapQueuedSpy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @program: spring-agent
 * @description:
 * @author: zt22328 赵儒定
 * @create: 2023-05-10 13:26
 **/
@Configuration
public class LogAlarmConfig {

    @Bean(initMethod = "start")
    @Order(Integer.MIN_VALUE)
    public AgentTemplate agentTemplate() {
        List<AgentVisitBase> visits = new ArrayList<>();
        visits.add(new AgentVisitBase(Throwable.class.getName(), ThrowableAdviceInterceptor.class, InterceptorType.CONSTRUCTOR));
        AgentVisitBase loggerAdvice = new AgentVisitBase(Logger.class.getName(), LoggerAdviceInterceptor.class, InterceptorType.METHOD);
        loggerAdvice.addMethodDefinition(new AgentVisitBase.MethodDefinition("callAppenders", ILoggingEvent.class.getName()));
        visits.add(loggerAdvice);
        AgentVisitBase threadPoolAdvice = new AgentVisitBase(ThreadPoolExecutor.class.getName(), ThreadPoolAdviceInterceptor.class, InterceptorType.CONSTRUCTOR_AND_METHOD);
        threadPoolAdvice.addMethodDefinition(new AgentVisitBase.MethodDefinition("reject", Runnable.class.getName()));
        visits.add(threadPoolAdvice);
        String spyClass = BootstrapQueuedSpy.class.getName();
        return new AgentTemplate(visits, spyClass);
    }

    @Bean
    public Repository repository() {
        return new MemoryRepository();
    }

    @Bean(initMethod = "start")
    public ErrorLogManager logManager(Repository repository, ThreadPoolManager threadPoolManager) {
        return new ErrorLogManager(repository, threadPoolManager);
    }

    @Bean(initMethod = "start")
    public ThreadPoolManager threadPoolManager() {
        return new ThreadPoolManager();
    }

}
